package org.zjvis.datascience.web.controller;

import static org.zjvis.datascience.common.util.ToolUtil.checkDuplicateName;

import cn.weiguangfu.swagger2.plus.annotation.ApiGroup;
import cn.weiguangfu.swagger2.plus.annotation.ApiPlus;
import cn.weiguangfu.swagger2.plus.enums.ApiExecutionEnum;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.zjvis.datascience.common.annotation.ProjectRoleAuth;
import org.zjvis.datascience.common.dto.ProjectDTO;
import org.zjvis.datascience.common.dto.ProjectNameDTO;
import org.zjvis.datascience.common.dto.TaskDTO;
import org.zjvis.datascience.common.enums.ActionEnum;
import org.zjvis.datascience.common.enums.ProjectRoleAuthEnum;
import org.zjvis.datascience.common.exception.BaseErrorCode;
import org.zjvis.datascience.common.exception.DataScienceException;
import org.zjvis.datascience.common.model.ApiResult;
import org.zjvis.datascience.common.model.ApiResultCode;
import org.zjvis.datascience.common.util.DozerUtil;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.common.vo.BaseVO;
import org.zjvis.datascience.common.vo.project.CreateProjectVO;
import org.zjvis.datascience.common.vo.project.ProjectIdVO;
import org.zjvis.datascience.common.vo.project.ProjectPageVO;
import org.zjvis.datascience.common.vo.project.ProjectVO;
import org.zjvis.datascience.common.vo.project.UpdateProjectVO;
import org.zjvis.datascience.service.ActionService;
import org.zjvis.datascience.service.ProjectService;
import org.zjvis.datascience.service.TaskService;
import org.zjvis.datascience.service.UserProjectService;

/**
 * @description 项目管理接口 Controller
 * @date 2021-11-03
 */
@ApiPlus(value = true)
@RestController
@RequestMapping("/projects")
@Api(tags = "project", description = "项目管理接口")
@Validated
public class ProjectController {

    private final static Logger logger = LoggerFactory.getLogger(ProjectController.class);

    @Autowired
    private ProjectService projectService;
    @Autowired
    private UserProjectService userProjectService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private ActionService actionService;

    @ApiGroup(groups = ProjectVO.Id.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/queryById")
    public ApiResult<ProjectDTO> queryById(@Validated(value = ProjectVO.Id.class) @RequestBody
    @ProjectRoleAuth(role = ProjectRoleAuthEnum.VISITOR, field = "id") ProjectVO vo) {
        ProjectDTO dto = DozerUtil.mapper(vo, ProjectDTO.class);
        return ApiResult.valueOf(userProjectService.queryProject(dto));
    }


    @ApiGroup(groups = ProjectVO.Id.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/clearProject")
    @ApiOperation(value = "清空操作", notes = "清空操作")
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> clearProject(@Validated(value = ProjectVO.Id.class) @RequestBody
    @ProjectRoleAuth(role = ProjectRoleAuthEnum.DEVELOPER, field = "id") ProjectVO vo) {
        if (vo.getId() == null || vo.getId() <= 0L) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }

        List<Long> taskIds = taskService.queryIdByProjectId(vo.getId());
        if (taskIds.size() == 0) {
            return ApiResult.valueOf(ApiResultCode.SUCCESS);
        }
        TaskDTO task = taskService.queryById(taskIds.get(0));
        Long pipelineId = task.getPipelineId();
        List<TaskDTO> deletedTasks = new ArrayList<>();
        JSONObject context = new JSONObject();
        taskService.batchDelete(context, taskIds, deletedTasks, pipelineId);
        actionService.addActionForTask(ActionEnum.DELETE, deletedTasks, null, null, context);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/query")
    public Object page(@Validated @RequestBody ProjectPageVO ppv) {
        if (StringUtils.isBlank(ppv.getSortColumn()) && StringUtils
            .isNotBlank(ppv.getSortMethod())) {
            throw new DataScienceException(BaseErrorCode.PROJECT_ORDER_1);
        } else if (StringUtils.isNotBlank(ppv.getSortMethod())) {
            if (!"asc".equalsIgnoreCase(ppv.getSortMethod().trim())
                && !"desc".equalsIgnoreCase(ppv.getSortMethod().trim())) {
                throw new DataScienceException(BaseErrorCode.PROJECT_ORDER_2);
            }
        }
        return ApiResult.valueOf(projectService.page(ppv));
    }

    @ApiGroup(groups = ProjectVO.Id.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/deleteById")
    @ResponseBody
    public ApiResult<Boolean> deleteById(@Validated(value = ProjectVO.Id.class) @RequestBody
    @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR, field = "id") ProjectVO vo) {
        try {
            userProjectService.deleteProject(DozerUtil.mapper(vo, ProjectDTO.class));
        }catch (DataScienceException e){
            return ApiResult.error(ApiResultCode.SYS_ERROR, e.getMessage());
        }
        return ApiResult.valueOf(true);

    }

    @ApiGroup(groups = BaseVO.Ignore.class, requestExecution = ApiExecutionEnum.EXCLUDE)
    @PostMapping(value = "/create")
    @ResponseBody
    @ApiOperation(value = "项目创建")
    public ApiResult<Long> create(@Valid @RequestBody CreateProjectVO vo) {
        ProjectDTO project = DozerUtil.mapper(vo, ProjectDTO.class);
        return ApiResult.valueOf(userProjectService.saveProject(project));
    }

    @ApiGroup(groups = BaseVO.Ignore.class, requestExecution = ApiExecutionEnum.EXCLUDE)
    @PostMapping(value = "/copy")
    @ResponseBody
    @ApiOperation(value = "项目复制")
    @Transactional
    public ApiResult<?> copy(@ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR) @RequestBody ProjectIdVO vo) {
        List<ProjectNameDTO> existProjects = projectService.queryProjectName(JwtUtil.getCurrentUserId());
        //获取当前project信息
        ProjectDTO template = projectService.query(vo.getProjectId());
        List<String> existNames = existProjects.stream().map(ProjectNameDTO::getName).collect(Collectors.toList());
        //重新赋值项目名和ID
        String newName = checkDuplicateName(template.getName() + "_复制", existNames);
        template.setName(newName);
        Long oldId = template.getId();
        template.setId(null);
        template.setGmtCreate(null);
        template.setGmtModify(null);
        //数据持久化
        long newId = userProjectService.saveProject(template);
        try{
            projectService.batchCopy(newId, oldId, false);
        }catch (DataScienceException e1){
            logger.warn("API /projects/copy failed, since {}", e1.getMessage());
            return e1.getApiResult();
        }
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @ApiGroup(groups = BaseVO.Ignore.class, requestExecution = ApiExecutionEnum.EXCLUDE)
    @PostMapping(value = "/template/copy")
    @ResponseBody
    @ApiOperation(value = "模板项目复制")
    @Transactional
    public ApiResult<?> copyTemplate(@ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR) @RequestBody ProjectIdVO vo) {
        //获取当前project信息
        ProjectDTO template = projectService.query(vo.getProjectId());
        //重新赋值项目名和ID
        template.setName(template.getName());
        Long oldId = template.getId();
        template.setGmtCreator(JwtUtil.getCurrentUserId());
        template.setGmtModifier(JwtUtil.getCurrentUserId());
        template.setId(null);
        template.setGmtCreate(null);
        template.setGmtModify(null);
        //数据持久化
        long newId = userProjectService.saveProject(template);
        try{
            projectService.batchCopy(newId, oldId, true);
        }catch (DataScienceException e1){
            logger.warn("API /projects/template/copy failed, since {}", e1.getMessage());
            return e1.getApiResult();
        }
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @ApiGroup(groups = UpdateProjectVO.Update.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/update")
    @ResponseBody
    public ApiResult<Boolean> update(
        @Valid @ProjectRoleAuth(role = ProjectRoleAuthEnum.ADMIN, field = "id", checkLock = true)
        @RequestBody UpdateProjectVO vo) {
        ProjectDTO project = DozerUtil.mapper(vo, ProjectDTO.class);
        userProjectService.updateProject(project);
        return ApiResult.valueOf(true);
    }

    @ApiGroup(groups = UpdateProjectVO.ChangeLockStatus.class, requestExecution = ApiExecutionEnum.INCLUDE)
    @PostMapping(value = "/changeStatus")
    @ResponseBody
    public ApiResult<Boolean> changeStatus(
        @Validated(value = UpdateProjectVO.ChangeLockStatus.class)
        @ProjectRoleAuth(role = ProjectRoleAuthEnum.ADMIN, field = "id") @RequestBody UpdateProjectVO vo) {
        ProjectDTO project = DozerUtil.mapper(vo, ProjectDTO.class);
        projectService.changeStatus(project);
        return ApiResult.valueOf(true);
    }

    @PostMapping(value = "/queryProjectName")
    public ApiResult<Object> queryProjectName() {
        List<ProjectNameDTO> res = projectService.queryProjectName(JwtUtil.getCurrentUserId());
        return ApiResult.valueOf(res);
    }

}
